﻿using Org.BouncyCastle.Utilities.Encoders;
using System.ComponentModel;
using System.Text;
using System.Web;

namespace AppWebApi.Utilities.SM4
{
    /// <summary>
    /// Sm4算法  
    /// 对标国际DES算法
    /// </summary>
    public class Sm4Crypto
    {
        public Sm4Crypto()
        {
            Key = "6166733764734d734a33357951363544";
            Iv = "sbnty74299507719";
            HexString = true;
            CryptoMode = Sm4CryptoMode.CBC;
        }
        /// <summary>
        /// 数据
        /// </summary>
        public string Data { get; set; }
        /// <summary>
        /// 秘钥
        /// </summary>
        public string Key { get; set; }
        /// <summary>
        /// 向量
        /// </summary>
        public string Iv { get; set; }
        /// <summary>
        /// 明文是否是十六进制
        /// </summary>
        public bool HexString { get; set; }
        /// <summary>
        /// 加密模式(默认ECB)
        /// </summary>
        public Sm4CryptoMode CryptoMode { get; set; }

        #region 加密
        public string Encrypt(Sm4Crypto entity)
        {
            return entity.CryptoMode == Sm4CryptoMode.CBC ? EncryptCBC(entity) : EncryptECB(entity);
        }
        /// <summary>
        /// ECB加密
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static string EncryptECB(Sm4Crypto entity)
        {
            Sm4Context ctx = new Sm4Context
            {
                IsPadding = true
            };

            byte[] keyBytes = entity.HexString ? Hex.Decode(entity.Key) : Encoding.Default.GetBytes(entity.Key);

            SM4 sm4 = new SM4();
            sm4.SetKeyEnc(ctx, keyBytes);
            byte[] encrypted = sm4.Sm4CryptEcb(ctx, Encoding.Default.GetBytes(entity.Data));

            return Encoding.Default.GetString(Hex.Encode(encrypted));
        }
        /// <summary>
        /// CBC加密
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static string EncryptCBC(Sm4Crypto entity)
        {
            Sm4Context ctx = new Sm4Context
            {
                IsPadding = true
            };

            byte[] keyBytes = entity.HexString ? Hex.Decode(entity.Key) : Encoding.Default.GetBytes(entity.Key);
            byte[] ivBytes = Encoding.Default.GetBytes(entity.Iv);
            // byte[] ivBytes = entity.HexString ? Hex.Decode(entity.Iv) : Encoding.Default.GetBytes(entity.Iv);

            SM4 sm4 = new SM4();
            sm4.SetKeyEnc(ctx, keyBytes);
            byte[] encrypted = sm4.Sm4CryptCbc(ctx, ivBytes, Encoding.Default.GetBytes(entity.Data));
            return Encoding.Default.GetString(Hex.Encode(encrypted));
            // return encrypted.ToBase64();
        }
        #endregion


        #region 解密
        public object Decrypt(Sm4Crypto entity)
        {
            return entity.CryptoMode == Sm4CryptoMode.CBC ? DecryptCBC(entity) : DecryptECB(entity);
        }
        /// <summary>
        ///  ECB解密
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public static string DecryptECB(Sm4Crypto entity)
        {
            Sm4Context ctx = new Sm4Context
            {
                IsPadding = true,
                Mode = 0
            };

            byte[] keyBytes = entity.HexString ? Hex.Decode(entity.Key) : Encoding.Default.GetBytes(entity.Key);

            SM4 sm4 = new SM4();
            sm4.Sm4SetKeyDec(ctx, keyBytes);
            byte[] decrypted = sm4.Sm4CryptEcb(ctx, Hex.Decode(entity.Data));
            return Encoding.Default.GetString(decrypted);
        }
        /// <summary>
        /// CBC解密
        /// </summary>
        /// <param name="cipherText"></param>
        /// <returns></returns>
        public static string DecryptCBC(Sm4Crypto entity)
        {
            Sm4Context ctx = new Sm4Context
            {
                IsPadding = true,
                Mode = 0
            };

            byte[] keyBytes = entity.HexString ? Hex.Decode(entity.Key) : Encoding.Default.GetBytes(entity.Key);
            byte[] ivBytes = Encoding.Default.GetBytes(entity.Iv);
            //byte[] ivBytes = entity.HexString ? Hex.Decode(entity.Iv) : Encoding.Default.GetBytes(entity.Iv);

            SM4 sm4 = new SM4();
            sm4.Sm4SetKeyDec(ctx, keyBytes);
            byte[] decrypted = sm4.Sm4CryptCbc(ctx, ivBytes, Hex.Decode(entity.Data));
            return Encoding.Default.GetString(decrypted);
        }
        #endregion

        public static string UrlEncode(string str)
        {
            StringBuilder builder = new StringBuilder();
            foreach (char c in str)
            {
                if (HttpUtility.UrlEncode(c.ToString()).Length > 1)
                {
                    builder.Append(HttpUtility.UrlEncode(c.ToString()).ToUpper());
                }
                else
                {
                    builder.Append(c);
                }
            }
            return builder.ToString();
        }

        /// <summary>
        /// 加密类型
        /// </summary>
        public enum Sm4CryptoMode
        {
            /// <summary>
            /// ECB(电码本模式)
            /// </summary>
            [Description("ECB模式")]
            ECB = 0,
            /// <summary>
            /// CBC(密码分组链接模式)
            /// </summary>
            [Description("CBC模式")]
            CBC = 1
        }
    }
}
